# -*- coding: utf-8 -*-
from w.settings import W
from w.html.format import TagFormatter
if W.HTML.ENABLE_STRICT_DYNAMIC_OBJECT:
#    from w.utils.dobject.strict import FDObject, DObject
    from w.utils.dobject.strict import DynamicInit, FilteredDynamicInit, DynamicAttribute
else:
#    from w.utils.dobject.quick import FDObject, DObject
    from w.utils.dobject.quick import DynamicInit, FilteredDynamicInit, DynamicAttribute
from w.utils.general import Object, isLikeList
from cgi import escape
import re
import sys

class Error(Exception): pass

class DocType(DynamicInit):
    def __str__(self):
        return self.docTypeTemplate % (self.name, self.spec)

class Cacheable(type):
    def __init__(cls, name, bases, dct):
        exceptions = ['HTMLTag','Tag','SingleTag']
        baseNames = [b.__name__ for b in bases]+[name]
        if not set(exceptions) & set(baseNames):
            setattr(cls, '_cache', {})

class ArgumentsCollector(FilteredDynamicInit):
    _argNameRE = re.compile('^h')

    escapedArguments = True

    minusReplacedBy = '__'
    argumentsLimiter = ' '
    argumentValueLimiter = ' '
    argumentFormat = '%s="%s"'

#----------------- css class field    
    def _setClass(self, val):
        raise Error('Class is a list, use ".append()" instead of "="')
    
    def _getClass(self):
        return self._html_class
    
    cssClass = property(fset=_setClass, fget=_getClass)
#-----------------

    def _prepare(self, obj):
        if isLikeList(obj):
            return self.argumentValueLimiter.join([str(s) for s in obj])
        return str(obj)

    def _nameHacks(self, s):
        return s.replace(self.minusReplacedBy,'-')

    def preFormat(self, name, value, esc):
        if esc:
            return (self._nameHacks(name),escape(self._prepare(value),quote=True))
        return (self._nameHacks(name),self._prepare(value))

    def generateArgsString(self):
        items = dict(self.html.__dict__)

        if self.cssClass:
            if 'Class' in items:
                cl = items['Class']
                cl = cl if isLikeList(cl) else [cl]
                items['Class'] = self.cssClass + cl
            else:
                items['Class'] = self.cssClass
        
        items = items.items()
        s=[self.argumentFormat%self.preFormat(n,v, self.escapedArguments) for n,v in items if v]

        return self.argumentsLimiter.join(s)
    
    def generateArgsID(self):
        l = self.html.__dict__.items()
        l.sort()
        return hash(tuple(l+[self.escapedArguments]))
    
    def __init__(self, escapedArguments=None, **vargs):
        if escapedArguments != None:
            self.escapedArguments=escapedArguments

        self._html_class = []
        self._collector = self.html = DynamicInit()
        FilteredDynamicInit.__init__(self,**vargs)

class ITag(list):
    _parent = None

    def make(self, content=[]):
        if not content:
            content = self
        def s(arg):
            try:
                if isinstance(arg, ITag):
                    return arg.make()
                return [str(arg)]
            except UnicodeDecodeError:
               return '?'
            except UnicodeEncodeError:
                return '?'
        return sum([s(e) for e in content], [])

    def __str__(self):
        return ''.join([str(e) for e in self.make()])
    

class HTMLTag(ArgumentsCollector, ITag):
    if W.HTML.ENABLE_CACHE:
        __metaclass__ = Cacheable

    _name = 'HTMLTag'
    
    escapedContent = True

    formatter = TagFormatter

TAG = HTMLTag

class Tag(HTMLTag):
    def __init__(self,content=None,escapedContent=None,**vargs):
        if escapedContent != None:
            self.escapedContent = escapedContent
        if isinstance(content,ITag):
            self.append(content)
        elif isLikeList(content):
            self.extend(content)
        elif content!=None:
            content = str(content)
            if self.escapedContent:
                content=escape(content)
            self.append(content)
            
        HTMLTag.__init__(self,**vargs)

    def __hash__(self):
#        return hash((self.generateArgsID(),hash(tuple(self))))
        return self.generateArgsID()

    if W.HTML.ENABLE_FORMAT:
        def __str__(self):
            if HTMLTag.formatter:
                return HTMLTag.formatter.formatTag(self, 
                            (self._name, self.generateArgsString(), self, self._name))
            return self.unformatted()
    elif W.HTML.ENABLE_CACHE:
        def __str__(self):
            ID = hash(self)
            if ID not in self.__class__._cache:
                self.__class__._cache[ID] = self.templated()
#            return self.__class__._cache[ID]%tuple(self)
            return self.__class__._cache[ID]%''.join([str(e) for e in self.make()])
    else:
        def __str__(self):
            return self.unformatted()

    def templated(self, level=0):
#        content = ''
#        cloned = list(self)
#        del self[:]
#        for e in cloned:
#            if sys.getrefcount(e) > 3+level:
#                content += '%s'
#                self.append(e)
#            elif isinstance(e,Tag):
#                self.extend(e)
#                content += e.templated(level+1)
#            else:
#                content += str(e)
#        return self.unformatted(content=content)
        return self.unformatted(content='%s')

class SingleTag(HTMLTag):
    if W.HTML.ENABLE_FORMAT:
        def __str__(self):
            if HTMLTag.formatter:
                return HTMLTag.formatter.formatSingleTag(self, 
                            (self._name, self.generateArgsString()))
            return self.unformatted()
    elif W.HTML.ENABLE_CACHE:
        def __str__(self):
            ID = self.generateArgsID()
            if ID not in self.__class__._cache:
                self.__class__._cache[ID] = self.templated()
            return self.__class__._cache[ID]
    else:
        def __str__(self):
            return self.unformatted()
        
    def templated(self):
        return self.unformatted()

